#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
/*
 * Copyright © 2014, Finium Sdn Bhd, All Rights Reserved
 * 
 * CharacterCheckingFilter.java
 * Modification History
 * *************************************************************
 * Date				Author						Comment
 * Sep 10, 2012		Venkaiah Chowdary Koneru	Created
 * Apr 08, 2013		Venkaiah Chowdary Koneru	Renamed to CharacterCheckingFilter from SecurityFilter.
 * *************************************************************
 */
package ${package}.commons.support;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import ${package}.support.CommonsUtil;

import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;

/**
 * Implementation of {@link javax.servlet.Filter} which checks for the special
 * characters in the web request.
 * 
 * @author Venkaiah Chowdary Koneru
 */
@WebFilter(urlPatterns = { "*.htm" }, filterName = "characterCheckingFilter",
        description = "Special Character Checking Filter")
public class CharacterCheckingFilter implements Filter
{
    private static final Log LOG = LogFactory
            .getLog(CharacterCheckingFilter.class);

    private FilterConfig filterConfig = null;
    private String errorPage = null;
    private Integer ajaxErrorStatusCode = null;

    /**
     * Called by the web container to indicate to a filter that it is being
     * placed into service.
     * 
     * The servlet container calls the init method exactly once after
     * instantiating the filter. The init method must complete successfully
     * before the filter is asked to do any filtering work.
     * 
     * @param filterConfig
     *            Contains configuration data of this particular filter
     */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException
    {
        Assert.notNull(filterConfig, "FilterConfig must not be null");

        LOG.debug("Initializing filter '" + filterConfig.getFilterName() + "'");

        this.filterConfig = filterConfig;
        this.errorPage = filterConfig.getInitParameter("errorPage");
        this.ajaxErrorStatusCode = Integer.valueOf(filterConfig
                .getInitParameter("ajaxErrorStatusCode"));

        LOG.debug("Filter '" + filterConfig.getFilterName()
                + "' configured successfully");
    }

    /**
     * Called by the web container to indicate to a filter that it is being
     * taken out of service.
     */
    @Override
    public void destroy()
    {
        LOG.debug("Destroying Security Filter...");
        filterConfig = null;
    }

    /**
     * The doFilter method of the Filter is called by the container each time a
     * request/response pair is passed through the chain due to a client request
     * for a resource at the end of the chain.
     * 
     * @param request
     *            current HTTP request
     * @param response
     *            current HTTP response
     * @param filterChain
     *            filter chain
     * 
     * @throws IOException
     *             in case of errors
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain filterChain) throws IOException, ServletException
    {
        if (request instanceof HttpServletRequest)
        {
            boolean authorized = true;

            HttpServletRequest httpServletRequest = (HttpServletRequest) request;

            // Prepare the request parameter map.
            Map<String, String[]> parameterMap = new HashMap<String, String[]>();

            if (!ServletFileUpload.isMultipartContent(httpServletRequest))
            {
                parameterMap = httpServletRequest.getParameterMap();
            }

            if (!CommonsUtil.isEmpty(parameterMap))
            {
                for (Map.Entry<String, String[]> entry : parameterMap
                        .entrySet())
                {
                    if (containsSpecial(entry.getValue()))
                    {
                        LOG.error("request parameter contains special characters: "
                                + entry.getValue()
                                + " for URL "
                                + httpServletRequest.getRequestURL());
                        authorized = false;
                        break;
                    }
                }
            }

            if (authorized)
            {
                filterChain.doFilter(new XssRequestWrapper(
                        (HttpServletRequest) request), response);
                return;
            }
            else
            {
                if (isAjaxRequest(httpServletRequest))
                {
                    LOG.error("found ajax request with special characters. Throwing Servlet exception so that ajax request will redirect to error page");
                    HttpServletResponse servletResponse = (HttpServletResponse) response;
                    servletResponse.setStatus(ajaxErrorStatusCode.intValue());
                    return;
                }
                else
                {
                    filterConfig
                            .getServletContext()
                            .getRequestDispatcher(errorPage)
                            .forward(
                                    new XssRequestWrapper(
                                            (HttpServletRequest) request),
                                    response);

                    return;
                }
            }
        }
    }

    /**
     * 
     * @param value
     * @return true if contains special characters otherwise false
     */
    private boolean containsSpecial(String... value)
    {
        // contain between a to z small cap --> [a-z]
        // contain between a to z big cap --> [A-Z]
        // contain between 0 to 9 --> [0-9]
        // *[^ --> and NOT (all the following symbol)
        for (String val : value)
        {
            // checking for ==> * ${symbol_dollar} < > | " ^
            if (!val.matches("(a-z|A-Z|0-9)*[^${symbol_escape}${symbol_escape}*${symbol_dollar}<>${symbol_escape}"^|]*${symbol_dollar}"))
            {
                return true;
            }
        }
        return false;
    }

    /**
     * Checks whether the request is originated from ajax call or normal
     * request.
     * 
     * @param httpServletRequest
     * @return true if request is ajax call otherwise false
     */
    private boolean isAjaxRequest(HttpServletRequest httpServletRequest)
    {
        final String flag = httpServletRequest.getHeader("X-Requested-With");

        if (flag != null && flag.equalsIgnoreCase("XMLHttpRequest"))
        {
            return true;
        }

        return false;
    }
}
